package org.apache.ibatis.datasource.unpooled;

import org.apache.ibatis.datasource.DataSourceException;
import org.apache.ibatis.datasource.DataSourceFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import javax.sql.DataSource;
import java.util.Properties;

/**
 * @author Clinton Begin
 */
public class UnpooledDataSourceFactory implements DataSourceFactory {

    private static final String DRIVER_PROPERTY_PREFIX = "driver.";
    private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();

    /**
     * 数据源(接口)
     */
    protected DataSource dataSource;

    /**
     * 构造函数
     * 生成简单数据源(非连接池)
     */
    public UnpooledDataSourceFactory() {
        // 创建 UnpooledDataSource 对象
        this.dataSource = new UnpooledDataSource();
    }

    /**
     * 设置DataSource的相关属性，一般紧跟在初始化完成之后
     *
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        Properties driverProperties = new Properties();
        // 创建DataSource相应的MetaObject
        MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
        // 遍历properties集合，该集合中配置了数据源需要的信息
        for (Object key : properties.keySet()) {
            String propertyName = (String) key;
            if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
                // 以"driver."开头的配置项是对DataSource的配置，记录到driverProperties中保存
                String value = properties.getProperty(propertyName);
                driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
            } else if (metaDataSource.hasSetter(propertyName)) {
                // 是否有该属性的setter方法
                String value = (String) properties.get(propertyName);
                // 根据属性类型进行类型转换，主要是Integer、Long、Boolean三种类型的转换
                Object convertedValue = convertValue(metaDataSource, propertyName, value);
                // 设置DataSource的相关属性值
                metaDataSource.setValue(propertyName, convertedValue);
            } else {
                throw new DataSourceException("Unknown DataSource property: " + propertyName);
            }
        }
        if (driverProperties.size() > 0) {
            // 设置DataSource.driverProperties属性值
            metaDataSource.setValue("driverProperties", driverProperties);
        }
    }

    /**
     * 获取DataSource对象
     *
     * @return
     */
    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 根据属性类型进行类型转换，主要是Integer、Long、Boolean三种类型的转换
     *
     * @param metaDataSource
     * @param propertyName
     * @param value
     * @return
     */
    private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {
        Object convertedValue = value;
        // 获取属性对应的 setter 方法的参数类型
        Class<?> targetType = metaDataSource.getSetterType(propertyName);
        // 按照 setter 方法的参数类型进行类型转换
        if (targetType == Integer.class || targetType == int.class) {
            convertedValue = Integer.valueOf(value);
        } else if (targetType == Long.class || targetType == long.class) {
            convertedValue = Long.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            convertedValue = Boolean.valueOf(value);
        }
        return convertedValue;
    }

}
